1 Exploratory Data Analysis, EDA

1.1 About EDA

EDA is an iterative cycle that helps you understand what your data says. When you do EDA, you:

  1. Generate questions about your data

  2. Search for answers by visualising, transforming, and/or modeling your data

  3. Use what you learn to refine your questions and/or generate new questions

EDA is an important part of any data analysis. You can use EDA to make discoveries about the world; or you can use EDA to ensure the quality of your data, asking questions about whether the data meets your standards or not. (Posit Primers: EDA)

1.2 Workflow

  1. Importing data by WDI
df_dataframe_name <- WDI(indicators = c(name1 = "Indicator Code 1", 
name2 = "Indicator Code 2"), extra = TRUE)

Write and read:

write_csv(df_dataframe_name, "data/dataframe_name.csv")
df_dataframe_name <- read_csv("data/dataframe_name.csv")
  1. Viewing data by

head(), str(), summary(), and try df_dataframe_name. See also Environment Tab of RStudio.

  1. Transforming data by restricting the values of a variable.
df_dataframe_name |> filter(var == "value") 
df_dataframe_name |> filter(var %in% c("value_1", ... , "value_n") 
df_dataframe_name |> filter(var != "value") 
df_dataframe_name |> drop_na(var)
  • Creating a new variable by mutation. (A little advanced. PCAP = gdp/pop)
df_dataframe_name |> mutate(var_new = var1 * var2)}
  1. Change orders by arrange()
df_dataframe_name |> arrange(var)
df_dataframe_name |> arrange(desc(var))
  1. Visualizing using ggplot() + geom_*()

    What type of variation occurs within my variables?

    What type of covariation occurs between my variables?

  • line graph
transformed_data |> ggplot(aes(year, name1)) + geom_line()
transformed_data |> ggplot(aes(year, name2)) + geom_line()
  • histogram
transformed_data |> ggplot(aes(name1)) + geom_histogram()
  • boxplot

categorical_var: factor(year), income, region

transformed_data |> ggplot(aes(categorical_var, name1)) + geom_boxplot()
  1. scatterplot
transformed_data |> ggplot(aes(name1, name2)) + geom_point()
transformed_data |> ggplot(aes(name1, name2)) + geom_point() + scale_x_log10()
  • scatterplot with a regression line
transformed_data |> ggplot(aes(name1, name2)) + geom_point() +
  geom_smooth(method = "lm", se = FALSE)
transformed_data |> ggplot(aes(name1, name2)) + geom_point() + 
  geom_smooth(method = "lm", se = FALSE) + scale_x_log10()
  1. Do not forget to add your observations and questions.

2 Example

2.1 CO2 Emissions Per Capita vs GDP Per Capita

An Example of EDA

Abstract. We study the relation between the CO2 emission per capita and the GDP per capita using two World Development Indicators.

2.1.1 Data

  1. CO2 emissions (metric tons per capita): EN.ATM.CO2E.PC [Link]
  • Description: Carbon dioxide emissions are those stemming from the burning of fossil fuels and the manufacture of cement. They include carbon dioxide produced during consumption of solid, liquid, and gas fuels and gas flaring.
  1. GDP per capita, PPP (constant 2017 international $): NY.GDP.PCAP.PP.KD [Link]
  • Description: GDP per capita based on purchasing power parity (PPP). PPP GDP is gross domestic product converted to international dollars using purchasing power parity rates. An international dollar has the same purchasing power over GDP as the U.S. dollar has in the United States. GDP at purchaser’s prices is the sum of gross value added by all resident producers in the country plus any product taxes and minus any subsidies not included in the value of the products. It is calculated without making deductions for depreciation of fabricated assets or for depletion and degradation of natural resources. Data are in constant 2017 international dollars.

2.1.2 Setup

library(tidyverse)
library(WDI)

If you do not have wdicache.rds in your data folder, run the following two code chunks.

wdicache <- WDIcache()

2.1.3 Description of data

WDIsearch with short = FALSE provides with the description of data in the last column.

WDIsearch(string = "EN.ATM.CO2E.PC", field = "indicator", 
          short = FALSE, cache = wdicache)

Description: Carbon dioxide emissions are those stemming from the burning of fossil fuels and the manufacture of cement. They include carbon dioxide produced during consumption of solid, liquid, and gas fuels and gas flaring.

WDIsearch(string = "NY.GDP.PCAP.PP.KD", field = "indicator", 
          short = FALSE, cache = wdicache)

Descritption: GDP per capita based on purchasing power parity (PPP). PPP GDP is gross domestic product converted to international dollars using purchasing power parity rates. An international dollar has the same purchasing power over GDP as the U.S. dollar has in the United States. GDP at purchaser’s prices is the sum of gross value added by all resident producers in the country plus any product taxes and minus any subsidies not included in the value of the products. It is calculated without making deductions for depreciation of fabricated assets or for depletion and degradation of natural resources. Data are in constant 2017 international dollars.

2.1.4 Importing and saving data

For extra information with extra = TRUE, we provide updated information with cache = wdicache.

df_co2gdp <- WDI(indicator = c(co2pcap = "EN.ATM.CO2E.PC", 
                               gdppcap = "NY.GDP.PCAP.PP.KD"),
                 extra = TRUE, cache = wdicache)
write_csv(df_co2gdp, "data/co2gdp.csv")
df_co2gdp <- read_csv("data/co2gdp.csv")
Rows: 16758 Columns: 14── Column specification ─────────────────────────────────────────────────
Delimiter: ","
chr  (7): country, iso2c, iso3c, region, capital, income, lending
dbl  (5): year, co2pcap, gdppcap, longitude, latitude
lgl  (1): status
date (1): lastupdated
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

2.1.5 Viewing and checking the data

Three ways to look at the table. df_co2gdp , head(df_co2gdp) , df_co2gdp under Environment tab in the top right pane.

df_co2gdp

If you do not add cache = wdicache when you download data with extra = TRUE, region and income of these countries would be NA as the country information attached to the package requires update using WDIcache(). As for Czechia and Viet Nam, see the file [Link] and its Addendum.

df_co2gdp |> filter(country %in% c("Czechia", "Viet Nam")) |>
  distinct(country, region, income)

2.1.5.1 Structure of data

glimpse(df_co2gdp) does about the same.

str(df_co2gdp)
spc_tbl_ [16,758 × 14] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ country    : chr [1:16758] "Afghanistan" "Afghanistan" "Afghanistan" "Afghanistan" ...
 $ iso2c      : chr [1:16758] "AF" "AF" "AF" "AF" ...
 $ iso3c      : chr [1:16758] "AFG" "AFG" "AFG" "AFG" ...
 $ year       : num [1:16758] 2012 2008 2009 2004 2011 ...
 $ status     : logi [1:16758] NA NA NA NA NA NA ...
 $ lastupdated: Date[1:16758], format: "2023-12-18" "2023-12-18" ...
 $ co2pcap    : num [1:16758] 0.3351 0.1656 0.2395 0.0549 0.409 ...
 $ gdppcap    : num [1:16758] 2123 1557 1824 1260 1961 ...
 $ region     : chr [1:16758] "South Asia" "South Asia" "South Asia" "South Asia" ...
 $ capital    : chr [1:16758] "Kabul" "Kabul" "Kabul" "Kabul" ...
 $ longitude  : num [1:16758] 69.2 69.2 69.2 69.2 69.2 ...
 $ latitude   : num [1:16758] 34.5 34.5 34.5 34.5 34.5 ...
 $ income     : chr [1:16758] "Low income" "Low income" "Low income" "Low income" ...
 $ lending    : chr [1:16758] "IDA" "IDA" "IDA" "IDA" ...
 - attr(*, "spec")=
  .. cols(
  ..   country = col_character(),
  ..   iso2c = col_character(),
  ..   iso3c = col_character(),
  ..   year = col_double(),
  ..   status = col_logical(),
  ..   lastupdated = col_date(format = ""),
  ..   co2pcap = col_double(),
  ..   gdppcap = col_double(),
  ..   region = col_character(),
  ..   capital = col_character(),
  ..   longitude = col_double(),
  ..   latitude = col_double(),
  ..   income = col_character(),
  ..   lending = col_character()
  .. )
 - attr(*, "problems")=<externalptr> 

2.1.5.2 Select columns

df_co2gdppcap <- df_co2gdp |> select(country, iso2c, year, co2pcap, gdppcap, region, income)

Check the distinct region names under the column region or income.

unique(df_co2gdppcap$region)
[1] "South Asia"                 "Aggregates"                
[3] "Europe & Central Asia"      "Middle East & North Africa"
[5] "East Asia & Pacific"        "Sub-Saharan Africa"        
[7] "Latin America & Caribbean"  "North America"             
[9] NA                          

The following does the same.

df_co2gdppcap |> distinct(region) |> pull()
[1] "South Asia"                 "Aggregates"                
[3] "Europe & Central Asia"      "Middle East & North Africa"
[5] "East Asia & Pacific"        "Sub-Saharan Africa"        
[7] "Latin America & Caribbean"  "North America"             
[9] NA                          

Using dput() may be handy if you want to use the output.

unique(df_co2gdppcap$income) |> dput()
c("Low income", "Aggregates", "Upper middle income", "Lower middle income", 
"High income", NA, "Not classified")
INCOME <-c("Low income", "Lower middle income", "Upper middle income", 
"High income")

It is possible to get the information in one code chunk.

df_co2gdppcap |> select(region, income) |> lapply(unique)
$region
[1] "South Asia"                 "Aggregates"                
[3] "Europe & Central Asia"      "Middle East & North Africa"
[5] "East Asia & Pacific"        "Sub-Saharan Africa"        
[7] "Latin America & Caribbean"  "North America"             
[9] NA                          

$income
[1] "Low income"          "Aggregates"          "Upper middle income"
[4] "Lower middle income" "High income"         NA                   
[7] "Not classified"     

2.1.6 Regions and Countries

It is convenient to have a list at hand.

wdicache$country |> filter(region == "Aggregates") |> 
  distinct(country, iso2c) 

Compare the following with above.

df_co2gdppcap |> filter(region == "Aggregates") |> 
  distinct(country, iso2c) 
df_co2gdppcap |> filter(is.na(region)) |> 
  distinct(country, iso2c) 

2.1.7 Countries

wdicache$country |> filter(region != "Aggregates") |> 
  distinct(country, iso2c, region, income) |> arrange(country)
df_co2gdppcap |> filter(region != "Aggregates") |> 
  distinct(country, iso2c, region, income) |> arrange(country)

Observations:

  • How can we get the difference easily?

2.1.8 Number of data of each year

Check whether you have enough data in each year.

df_co2gdppcap |> drop_na(co2pcap, gdppcap) |>
  ggplot(aes(year)) + geom_bar()

Observation:

  • The data starts in the year 1990 and ends in 2020. There are data of over 200 countries and regions.

The code above is same as the following.

df_co2gdppcap |> drop_na(co2pcap, gdppcap) |>
  group_by(year) |> summarize(n = n()) |>
  ggplot(aes(year, n)) + geom_col()

2.1.9 Visualization by Line Graphs

2.1.9.1 CO2 per capita

COUNTRY <- "World"
df_co2gdppcap |> filter(country == COUNTRY) |> drop_na(co2pcap) |>
  ggplot(aes(year, co2pcap)) + geom_line() +
  labs(title = expression(paste(CO[2], " per capita of the World")),
       y = expression(paste(CO[2], " per capita in tons")))

Observations:

  • CO2 per capita of the World is decreasing but not much.
ISO2C <- c("JP", "CN", "ID", "GB", "US", "DE", "FR")
df_co2gdppcap |> filter(iso2c %in% ISO2C) |> drop_na(co2pcap) |>
  ggplot(aes(year, co2pcap, col = iso2c)) + geom_line() +
  labs(title = expression(paste(CO[2], " per capita of seven conutries with large GDP")),
       subtitle = "China, Germany, France, United Kingdom, India, Japan, United States", 
       y = expression(paste(CO[2], " per capita in tons")))

Observations:

  • Need to study more in detail.

2.1.9.2 GDP per capita

COUNTRY <- "World"
df_co2gdppcap |> filter(country == COUNTRY) |> drop_na(gdppcap) |>
  ggplot(aes(year, gdppcap)) + geom_line() +
  labs(title = "GDP per capita of the World")

Observations:

  • There are two drops but increasing steadily.
ISO2C <- c("JP", "CN", "ID", "GB", "US", "DE", "FR")
df_co2gdppcap |> filter(iso2c %in% ISO2C) |> drop_na(gdppcap) |>
  ggplot(aes(year, gdppcap, col = iso2c)) + geom_line() +
  labs(title = "GDP per capita of seven countries with large GDP",
       subtitle = "China, Germany, France, United Kingdom, India, Japan, United States", 
       y = "GDP per capita PPP",
       caption = "constant 2017 international usd")

Observations:

  • Need to study each in detail.

2.1.9.3 Ranking of CO2 per capita

df_co2gdppcap |> filter(year == 2020) |> filter(region != "Aggregates") |>
  drop_na(co2pcap) |> arrange(desc(co2pcap))

Observations:

  • Many oil producing countries are on the top.
df_co2gdppcap |> filter(year == 2020) |> filter(region != "Aggregates") |>
  drop_na(co2pcap) |> arrange(co2pcap)

Observations and Questions:

  • Top 10 countries of CO2 emission per capita:

    • Qtar, Bahrain, Brunei Darussalam, Kuwait, United Arab Emirates, Oman, Australia, Saudi Arabia, Canada, and United States
  • Lowest 10 countries of CO2 emission per capita:

    • Congo, Dem. Rep., Somalia, Central African Republic, Burundi, Malawi, Niger, Chad, Madagascar, Rwanda, Sierra Leone
  • The top 10 is about 1000 times the bottom 10.

2.1.9.4 Ranking of GDP per capita

df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates") |>
  drop_na(gdppcap) |> arrange(desc(gdppcap))

Observations:

  • Interesting. I know the ranking of GDP but not GDP per capita.
df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates") |>
  drop_na(gdppcap) |> arrange(gdppcap)

Observations:

  • Top 10 is about 100 times the bottom 10.

2.1.10 Histograms and Boxplots for Variation

2.1.10.1 CO2 per capita

Change the bins or binwidth.

df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates") |> drop_na(co2pcap) |> 
  ggplot(aes(co2pcap)) + geom_histogram()

df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates") |> drop_na(co2pcap) |> 
  ggplot(aes(co2pcap)) + geom_histogram(bins = 10)

Observations:

  • For most of the countries, the value is less than 5 tons per person per year.
df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates") |> drop_na(co2pcap) |> 
  ggplot(aes(co2pcap, fill = region)) + geom_histogram(bins = 15, col = "black", linewidth = 0.2)

Observations:

  • Interesting but complicated.
df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates") |> drop_na(co2pcap) |> 
  ggplot(aes(co2pcap, fill = factor(income, levels = INCOME))) + geom_histogram(bins = 15, col = "black", linewidth = 0.2) +
  labs(fill = "")

Observations and Questions:

  • High income countries have larger values in general.
df_co2gdppcap |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(co2pcap) |> filter(income != "Not classified") |>
  ggplot(aes(co2pcap, fill = factor(income, levels = INCOME))) + geom_histogram(bins = 15, col = "black", linewidth = 0.1) + 
  scale_x_log10() +
  labs(title = "Histogram of CO2 per capita in 2020", fill = "")

Observations:

  • Each of log10 scale and the raw value seems to tell different feature.

  • Need to consider NA value in income.

df_co2gdppcap |> filter(year %in% c(1990, 2000, 2010, 2020)) |> filter(region != "Aggregates") |> 
  drop_na(co2pcap) |> filter(co2pcap > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(co2pcap, fill = factor(year))) + 
  geom_histogram(bins = 15, col = "black", linewidth = 0.1) + 
  scale_x_log10() + facet_wrap(~year) +
  labs(title = "Histogram of CO2 per capita in 1990, 2000, 2010, 2020", fill = "")

Observations:

  • Want old data, but can see differences.
df_co2gdppcap |> filter(year %in% c(1990, 2000, 2010, 2020)) |> filter(region != "Aggregates") |> 
  drop_na(co2pcap) |> filter(co2pcap > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(co2pcap, factor(year), fill = factor(year))) + 
  geom_boxplot() + scale_x_log10() + labs(y = "") + theme(legend.position = "none")

Observations:

  • Not much different but the width is decreasing.
df_co2gdppcap |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(co2pcap) |> filter(co2pcap > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(co2pcap, factor(income, levels = INCOME), fill = income)) + 
  geom_boxplot() + scale_x_log10() + 
  labs(title = "CO2 per capita by income level", y = "", fill = "") +
  theme(legend.position = "none")

Observations:

  • The result looks natural. However, it is worth analysing outliers in detail.
df_co2gdppcap |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(co2pcap) |> filter(co2pcap > 0) |> 
  ggplot(aes(co2pcap, region, fill = region)) + 
  geom_boxplot() + scale_x_log10() + 
  labs(title = "CO2 per capita by region", y = "", fill = "") +
  theme(legend.position = "none")

Observations:

  • Need to investigate each region closely.

2.1.10.2 GDP per capita

df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates", !is.na(income)) |>
  drop_na(gdppcap) |> ggplot(aes(gdppcap, factor(income, levels = INCOME), fill = income)) + geom_boxplot() + scale_x_log10() + theme(legend.position = "none") + labs(y = "")

Observations:

  • There are overlaps. Need to study how the income level is determined by World Bank.

    • How does the World Bank classify countries? [Link]
df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates", !is.na(region)) |>
  drop_na(gdppcap) |>
  ggplot(aes(gdppcap, fill = region)) + geom_histogram(bins = 15, col = "black", linewidth = 0.2) + 
  labs(fill = "")

Observations:

  • Interesting but complicated.
df_co2gdppcap |> filter(year == 2020) |> 
  filter(region != "Aggregates", !is.na(region)) |>
  drop_na(gdppcap) |>
  ggplot(aes(gdppcap, fill = region)) + geom_histogram(bins = 15, col = "black", linewidth = 0.2) + scale_x_log10() +
  labs(fill = "")

Observations:

  • Two scales give different information and impression.
df_co2gdppcap |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(gdppcap) |> filter(income != "Not classified") |>
  ggplot(aes(gdppcap, fill = factor(income, levels = INCOME))) + geom_histogram(bins = 15, col = "black", linewidth = 0.1) + 
  scale_x_log10() +
  labs(title = "Histogram of GDP per capita in 2020", fill = "")

Observations:

  • Need to study overlaps.
df_co2gdppcap |> filter(year %in% c(1990, 2000, 2010, 2020)) |> filter(region != "Aggregates") |> 
  drop_na(gdppcap) |> filter(gdppcap > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(gdppcap, fill = factor(year))) + 
  geom_histogram(bins = 15, col = "black", linewidth = 0.1) + 
  scale_x_log10() + facet_wrap(~year) +
  labs(title = "Histogram of GDP per capita in 1990, 2000, 2010, 2020", fill = "") +
  theme(legend.position = "none")

Observations:

  • Cannot see a big difference.
df_co2gdppcap |> filter(year %in% c(1990, 2000, 2010, 2020)) |> filter(region != "Aggregates") |> 
  drop_na(gdppcap) |> filter(gdppcap > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(gdppcap, factor(year), fill = factor(year))) + 
  geom_boxplot() + scale_x_log10() + labs(y = "") + theme(legend.position = "none")

Observations:

  • Not much can be seen.
df_co2gdppcap |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(gdppcap) |> filter(gdppcap > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(gdppcap, factor(income, levels = INCOME), fill = income)) + 
  geom_boxplot() + scale_x_log10() + 
  labs(title = "GDP per capita by income level", y = "", fill = "") +
  theme(legend.position = "none")

Observations:

  • Can see a trend.
df_co2gdppcap |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(gdppcap) |> filter(gdppcap > 0) |> 
  ggplot(aes(gdppcap, region, fill = region)) + 
  geom_boxplot() + scale_x_log10() + 
  labs(title = "GDP per capita by region", y = "", fill = "") +
  theme(legend.position = "none")

Observations:

  • What is the best way to look at regional differences?

2.1.11 Scatterplot for Covariation

2.1.11.1 Scatterplot with a regression line

df_co2gdppcap |> filter(year == 2020) |> 
  drop_na(gdppcap, co2pcap) |>
  ggplot(aes(gdppcap, co2pcap)) + geom_point(aes(col = region)) +
  geom_smooth(method = "lm", formula = 'y~x', se = FALSE) +
  scale_x_log10() + scale_y_log10() +
  labs(title = "GDP per capita vs CO2 per capita",
       x = "GDP per capita",
       y = expression(paste(CO[2], " per capita in tons")))

Observations:

  • GDP per capita in log10 scale and Co2 per capita relates positively and the regression line looks well-fit.

2.1.11.2 Summary of a linear model

You will learn how to interprete the values below later in this course.

df_co2gdppcap |> filter(year == 2020) |> drop_na(gdppcap, co2pcap) |>
  lm(log10(co2pcap)~log10(gdppcap), data = _) |> summary()

Call:
lm(formula = log10(co2pcap) ~ log10(gdppcap), data = drop_na(filter(df_co2gdppcap, 
    year == 2020), gdppcap, co2pcap))

Residuals:
     Min       1Q   Median       3Q      Max 
-0.68315 -0.15741 -0.00445  0.16201  0.59504 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)    -4.31720    0.13473  -32.04   <2e-16 ***
log10(gdppcap)  1.13857    0.03309   34.41   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2375 on 228 degrees of freedom
Multiple R-squared:  0.8385,    Adjusted R-squared:  0.8378 
F-statistic:  1184 on 1 and 228 DF,  p-value: < 2.2e-16

Observations:

  • In log10 scale, the regression line fits well with slope 1.1.

  • Multiple R-square is 0.84 and the linear regression explains good part of the relation of these data.

3 Your Project

3.1 Title of your project

We study …..

  1. Name of the indicator 1: Indicator Code 1
  • Description:
  1. Name of the indicator 2: Indicator Code 2
  • Description:

3.1.1 Importing Data

Edit the following code chunk!
chosen_indicator_1 <- "SE.SEC.ENRR" #example
short_name_1 <- "sec"
chosen_indicator_2 <- "NY.GDP.PCAP.PP.KD" #example
short_name_2 <- "gdppcap"
df_yourdata <- WDI(indicator = c(short_name_1 = chosen_indicator_1,
                                 short_name_2 = chosen_indicator_2),
                 extra = TRUE, cache = wdicache)
write_csv(df_yourdata, "data/yourdata.csv")
df_yourdata <- read_csv("data/yourdata.csv")
Rows: 16758 Columns: 14── Column specification ─────────────────────────────────────────────────
Delimiter: ","
chr  (7): country, iso2c, iso3c, region, capital, income, lending
dbl  (5): year, short_name_1, short_name_2, longitude, latitude
lgl  (1): status
date (1): lastupdated
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

3.1.2 Visualization by Line Graphs

3.1.2.1 Name of the Indicator 1

Edit the title and the label of y-axis.
COUNTRY <- "World"
df_yourdata |> filter(country == COUNTRY) |> drop_na(short_name_1) |>
  ggplot(aes(year, short_name_1)) + geom_line() +
  labs(title = "",
       y = "")

Observations and Questions:

Edit ISO2C, title, subtitle, and the label of y-axis.
ISO2C <- c("JP", "CN", "ID", "GB", "US", "DE", "FR")
df_yourdata |> filter(iso2c %in% ISO2C) |> drop_na(short_name_1) |>
  ggplot(aes(year, short_name_1, col = iso2c)) + geom_line() +
  labs(title = "",
       subtitle = "China, Germany, France, United Kingdom, India, Japan, United States", 
       y = "")

Observations and Questions:

3.1.2.2 Name of the Indicator 2

Edit COUNTRY and the title.
COUNTRY <- "World"
df_yourdata |> filter(country == COUNTRY) |> drop_na(short_name_2) |>
  ggplot(aes(year, short_name_2)) + geom_line() +
  labs(title = "")

Observations and Questions:

Edit ISO2C, title, subtitle, and the label of y-axis, and add caption if preferable.
ISO2C <- c("JP", "CN", "ID", "GB", "US", "DE", "FR")
df_yourdata |> filter(iso2c %in% ISO2C) |> drop_na(short_name_2) |>
  ggplot(aes(year, short_name_2, col = iso2c)) + geom_line() +
  labs(title = "",
       subtitle = "China, Germany, France, United Kingdom, India, Japan, United States", 
       y = "",
       caption = "")

Observations and Questions:

3.1.2.3 Ranking of the indicator 1

Edit year if necessary.
df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |>
  drop_na(short_name_1) |> arrange(desc(short_name_1))
df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |>
  drop_na(short_name_1) |> arrange(short_name_1)

Observations and Questions:

3.1.2.4 Ranking of the Indicator 2

df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |>
  drop_na(short_name_2) |> arrange(desc(short_name_2))

Observations and Questions:

df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |>
  drop_na(short_name_2) |> arrange(short_name_2)

Observations and Questions:

3.1.3 Histograms and Boxplots for Variation

3.1.3.1 Name of the Indicator 1

Edit the title and year.
df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(short_name_1) |> filter(income != "Not classified") |>
  ggplot(aes(short_name_1, fill = factor(income, levels = INCOME))) + geom_histogram(bins = 15, col = "black", linewidth = 0.1) + 
  scale_x_log10() +
  labs(title = "", fill = "")

Observations and Questions:

Edit the title and the years.
df_yourdata |> filter(year %in% c(1990, 2000, 2010, 2020)) |> filter(region != "Aggregates") |> 
  drop_na(short_name_1) |> filter(short_name_1 > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(short_name_1, fill = factor(year))) + 
  geom_histogram(bins = 15, col = "black", linewidth = 0.1) + 
  scale_x_log10() + facet_wrap(~year) +
  labs(title = "", fill = "")

Observations and Questions:

df_yourdata |> filter(year %in% c(1990, 2000, 2010, 2020)) |> filter(region != "Aggregates") |> 
  drop_na(short_name_1) |> filter(short_name_1 > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(short_name_1, factor(year), fill = factor(year))) + 
  geom_boxplot() + scale_x_log10() + labs(y = "") + theme(legend.position = "none")

Observations and Questions:

Edit the title, and the year if necessary.
df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(short_name_1) |> filter(short_name_1 > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(short_name_1, factor(income, levels = INCOME), fill = income)) + 
  geom_boxplot() + scale_x_log10() + 
  labs(title = "", y = "", fill = "") +
  theme(legend.position = "none")

Observations and Questions:

Edit the title and year if necessary.
df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(short_name_1) |> filter(short_name_1 > 0) |> 
  ggplot(aes(short_name_1, region, fill = region)) + 
  geom_boxplot() + scale_x_log10() + 
  labs(title = "", y = "", fill = "") +
  theme(legend.position = "none")

Observations and Questions:

3.1.3.2 GDP per capita

Edit the title, and year if necessary.
df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(short_name_2) |> filter(income != "Not classified") |>
  ggplot(aes(short_name_2, fill = factor(income, levels = INCOME))) + geom_histogram(bins = 15, col = "black", linewidth = 0.1) + 
  scale_x_log10() +
  labs(title = "", fill = "")

Edit the title and the year if necessary.
df_yourdata |> filter(year %in% c(1990, 2000, 2010, 2020)) |> filter(region != "Aggregates") |> 
  drop_na(short_name_2) |> filter(short_name_2 > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(short_name_2, fill = factor(year))) + 
  geom_histogram(bins = 15, col = "black", linewidth = 0.1) + 
  scale_x_log10() + facet_wrap(~year) +
  labs(title = "", fill = "") +
  theme(legend.position = "none")

Observations and Questions:

df_yourdata |> filter(year %in% c(1990, 2000, 2010, 2020)) |> filter(region != "Aggregates") |> 
  drop_na(short_name_2) |> filter(short_name_2 > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(short_name_2, factor(year), fill = factor(year))) + 
  geom_boxplot() + scale_x_log10() + labs(y = "") + theme(legend.position = "none")

Observations and Questions:

Edit the title, and the year if necessary.
df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(short_name_2) |> filter(short_name_2 > 0) |> filter(income != "Not classified") |> 
  ggplot(aes(short_name_2, factor(income, levels = INCOME), fill = income)) + 
  geom_boxplot() + scale_x_log10() + 
  labs(title = "", y = "", fill = "") +
  theme(legend.position = "none")

Observations and Questions:

Edit the title and the year if necessary.
df_yourdata |> filter(year == 2020) |> filter(region != "Aggregates") |> 
  drop_na(short_name_2) |> filter(short_name_2 > 0) |> 
  ggplot(aes(short_name_2, region, fill = region)) + 
  geom_boxplot() + scale_x_log10() + 
  labs(title = "", y = "", fill = "") +
  theme(legend.position = "none")

3.1.4 Scatterplot for Covariation

3.1.4.1 Scatterplot with a regression line

Edit the title, the labels of x- and y- axes.
df_yourdata |> filter(year == 2020) |> 
  drop_na(short_name_2, short_name_1) |>
  ggplot(aes(short_name_2, short_name_1)) + geom_point(aes(col = region)) +
  geom_smooth(method = "lm", formula = 'y~x', se = FALSE) +
  scale_x_log10() + scale_y_log10() +
  labs(title = "",
       x = "",
       y = "")

Observations and Questions:

3.1.4.2 Summary of a linear model

Edit year if necessary.
df_yourdata |> filter(year == 2020) |> drop_na(short_name_2, short_name_1) |>
  lm(log10(short_name_1)~log10(short_name_2), data = _) |> summary()

Call:
lm(formula = log10(short_name_1) ~ log10(short_name_2), data = drop_na(filter(df_yourdata, 
    year == 2020), short_name_2, short_name_1))

Residuals:
      Min        1Q    Median        3Q       Max 
-0.279981 -0.058887  0.003311  0.063366  0.246949 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)          0.81316    0.06423   12.66   <2e-16 ***
log10(short_name_2)  0.26533    0.01532   17.32   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.08889 on 172 degrees of freedom
Multiple R-squared:  0.6356,    Adjusted R-squared:  0.6335 
F-statistic: 300.1 on 1 and 172 DF,  p-value: < 2.2e-16

Observations and Questions:

LS0tCnRpdGxlOiAiRURBIHVzaW5nIFdESSIKYXV0aG9yOiAiSUQgTGFzdCwgRmlyc3QiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzLCBFREEKCiMjIEFib3V0IEVEQQoKRURBIGlzIGFuIGl0ZXJhdGl2ZSBjeWNsZSB0aGF0IGhlbHBzIHlvdSB1bmRlcnN0YW5kIHdoYXQgeW91ciBkYXRhIHNheXMuIFdoZW4geW91IGRvIEVEQSwgeW91OgoKMS4gIEdlbmVyYXRlIHF1ZXN0aW9ucyBhYm91dCB5b3VyIGRhdGEKCjIuICBTZWFyY2ggZm9yIGFuc3dlcnMgYnkgdmlzdWFsaXNpbmcsIHRyYW5zZm9ybWluZywgYW5kL29yIG1vZGVsaW5nIHlvdXIgZGF0YQoKMy4gIFVzZSB3aGF0IHlvdSBsZWFybiB0byByZWZpbmUgeW91ciBxdWVzdGlvbnMgYW5kL29yIGdlbmVyYXRlIG5ldyBxdWVzdGlvbnMKCkVEQSBpcyBhbiBpbXBvcnRhbnQgcGFydCBvZiBhbnkgZGF0YSBhbmFseXNpcy4gWW91IGNhbiB1c2UgRURBIHRvIG1ha2UgZGlzY292ZXJpZXMgYWJvdXQgdGhlIHdvcmxkOyBvciB5b3UgY2FuIHVzZSBFREEgdG8gZW5zdXJlIHRoZSBxdWFsaXR5IG9mIHlvdXIgZGF0YSwgYXNraW5nIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSBkYXRhIG1lZXRzIHlvdXIgc3RhbmRhcmRzIG9yIG5vdC4gKFBvc2l0IFByaW1lcnM6IFtFREFdKGh0dHBzOi8vcG9zaXQuY2xvdWQvbGVhcm4vcHJpbWVycy8zLjEpKQoKIyMgV29ya2Zsb3cKCjEuICBJbXBvcnRpbmcgZGF0YSBieSBXREkKCmBgYCAgICAgICAgIApkZl9kYXRhZnJhbWVfbmFtZSA8LSBXREkoaW5kaWNhdG9ycyA9IGMobmFtZTEgPSAiSW5kaWNhdG9yIENvZGUgMSIsIApuYW1lMiA9ICJJbmRpY2F0b3IgQ29kZSAyIiksIGV4dHJhID0gVFJVRSkKYGBgCgpXcml0ZSBhbmQgcmVhZDoKCmBgYCAgICAgICAgIAp3cml0ZV9jc3YoZGZfZGF0YWZyYW1lX25hbWUsICJkYXRhL2RhdGFmcmFtZV9uYW1lLmNzdiIpCmRmX2RhdGFmcmFtZV9uYW1lIDwtIHJlYWRfY3N2KCJkYXRhL2RhdGFmcmFtZV9uYW1lLmNzdiIpCmBgYAoKMi4gIFZpZXdpbmcgZGF0YSBieQoKYGhlYWQoKWAsIGBzdHIoKWAsIGBzdW1tYXJ5KClgLCBhbmQgdHJ5IGBkZl9kYXRhZnJhbWVfbmFtZWAuIFNlZSBhbHNvIEVudmlyb25tZW50IFRhYiBvZiBSU3R1ZGlvLgoKMy4gIFRyYW5zZm9ybWluZyBkYXRhIGJ5IHJlc3RyaWN0aW5nIHRoZSB2YWx1ZXMgb2YgYSB2YXJpYWJsZS4KCmBgYCAgICAgICAgIApkZl9kYXRhZnJhbWVfbmFtZSB8PiBmaWx0ZXIodmFyID09ICJ2YWx1ZSIpIApkZl9kYXRhZnJhbWVfbmFtZSB8PiBmaWx0ZXIodmFyICVpbiUgYygidmFsdWVfMSIsIC4uLiAsICJ2YWx1ZV9uIikgCmRmX2RhdGFmcmFtZV9uYW1lIHw+IGZpbHRlcih2YXIgIT0gInZhbHVlIikgCmRmX2RhdGFmcmFtZV9uYW1lIHw+IGRyb3BfbmEodmFyKQpgYGAKCi0gICBDcmVhdGluZyBhIG5ldyB2YXJpYWJsZSBieSBtdXRhdGlvbi4gKEEgbGl0dGxlIGFkdmFuY2VkLiBQQ0FQID0gZ2RwL3BvcCkKCmBgYCAgICAgICAgIApkZl9kYXRhZnJhbWVfbmFtZSB8PiBtdXRhdGUodmFyX25ldyA9IHZhcjEgKiB2YXIyKX0KYGBgCgo0LiAgQ2hhbmdlIG9yZGVycyBieSBgYXJyYW5nZSgpYAoKYGBgICAgICAgICAgCmRmX2RhdGFmcmFtZV9uYW1lIHw+IGFycmFuZ2UodmFyKQpkZl9kYXRhZnJhbWVfbmFtZSB8PiBhcnJhbmdlKGRlc2ModmFyKSkKYGBgCgo1LiAgVmlzdWFsaXppbmcgdXNpbmcgZ2dwbG90KCkgKyBnZW9tXF9cKigpCgogICAgV2hhdCB0eXBlIG9mwqAqKnZhcmlhdGlvbioqwqBvY2N1cnPCoCoqd2l0aGluKirCoG15IHZhcmlhYmxlcz8KCiAgICBXaGF0IHR5cGUgb2bCoCoqY292YXJpYXRpb24qKsKgb2NjdXJzwqAqKmJldHdlZW4qKsKgbXkgdmFyaWFibGVzPwoKLSAgIGxpbmUgZ3JhcGgKCmBgYCAgICAgICAgIAp0cmFuc2Zvcm1lZF9kYXRhIHw+IGdncGxvdChhZXMoeWVhciwgbmFtZTEpKSArIGdlb21fbGluZSgpCnRyYW5zZm9ybWVkX2RhdGEgfD4gZ2dwbG90KGFlcyh5ZWFyLCBuYW1lMikpICsgZ2VvbV9saW5lKCkKYGBgCgotICAgaGlzdG9ncmFtCgpgYGAgICAgICAgICAKdHJhbnNmb3JtZWRfZGF0YSB8PiBnZ3Bsb3QoYWVzKG5hbWUxKSkgKyBnZW9tX2hpc3RvZ3JhbSgpCmBgYAoKLSAgIGJveHBsb3QKCmBjYXRlZ29yaWNhbF92YXJgOiBgZmFjdG9yKHllYXIpYCwgYGluY29tZWAsIGByZWdpb25gCgpgYGAgICAgICAgICAKdHJhbnNmb3JtZWRfZGF0YSB8PiBnZ3Bsb3QoYWVzKGNhdGVnb3JpY2FsX3ZhciwgbmFtZTEpKSArIGdlb21fYm94cGxvdCgpCmBgYAoKNi4gIHNjYXR0ZXJwbG90CgpgYGAgICAgICAgICAKdHJhbnNmb3JtZWRfZGF0YSB8PiBnZ3Bsb3QoYWVzKG5hbWUxLCBuYW1lMikpICsgZ2VvbV9wb2ludCgpCnRyYW5zZm9ybWVkX2RhdGEgfD4gZ2dwbG90KGFlcyhuYW1lMSwgbmFtZTIpKSArIGdlb21fcG9pbnQoKSArIHNjYWxlX3hfbG9nMTAoKQpgYGAKCi0gICBzY2F0dGVycGxvdCB3aXRoIGEgcmVncmVzc2lvbiBsaW5lCgpgYGAgICAgICAgICAKdHJhbnNmb3JtZWRfZGF0YSB8PiBnZ3Bsb3QoYWVzKG5hbWUxLCBuYW1lMikpICsgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKQp0cmFuc2Zvcm1lZF9kYXRhIHw+IGdncGxvdChhZXMobmFtZTEsIG5hbWUyKSkgKyBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArIHNjYWxlX3hfbG9nMTAoKQpgYGAKCjcuICBEbyBub3QgZm9yZ2V0IHRvIGFkZCB5b3VyIG9ic2VydmF0aW9ucyBhbmQgcXVlc3Rpb25zLgoKIyBFeGFtcGxlCgojIyBDT34yfiBFbWlzc2lvbnMgUGVyIENhcGl0YSB2cyBHRFAgUGVyIENhcGl0YQoKKkFuIEV4YW1wbGUgb2YgRURBKgoKPiAqKkFic3RyYWN0LioqIFdlIHN0dWR5IHRoZSByZWxhdGlvbiBiZXR3ZWVuIHRoZSBDT34yfiBlbWlzc2lvbiBwZXIgY2FwaXRhIGFuZCB0aGUgR0RQIHBlciBjYXBpdGEgdXNpbmcgdHdvIFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvcnMuCgojIyMgRGF0YQoKMS4gIENPMiBlbWlzc2lvbnMgKG1ldHJpYyB0b25zIHBlciBjYXBpdGEpOiBFTi5BVE0uQ08yRS5QQyBbW0xpbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9FTi5BVE0uQ08yRS5QQyldCgotICAgRGVzY3JpcHRpb246IENhcmJvbiBkaW94aWRlIGVtaXNzaW9ucyBhcmUgdGhvc2Ugc3RlbW1pbmcgZnJvbSB0aGUgYnVybmluZyBvZiBmb3NzaWwgZnVlbHMgYW5kIHRoZSBtYW51ZmFjdHVyZSBvZiBjZW1lbnQuIFRoZXkgaW5jbHVkZSBjYXJib24gZGlveGlkZSBwcm9kdWNlZCBkdXJpbmcgY29uc3VtcHRpb24gb2Ygc29saWQsIGxpcXVpZCwgYW5kIGdhcyBmdWVscyBhbmQgZ2FzIGZsYXJpbmcuCgoyLiAgR0RQIHBlciBjYXBpdGEsIFBQUCAoY29uc3RhbnQgMjAxNyBpbnRlcm5hdGlvbmFsIFwkKTogTlkuR0RQLlBDQVAuUFAuS0QgW1tMaW5rXShodHRwczovL2RhdGEud29ybGRiYW5rLm9yZy9pbmRpY2F0b3IvTlkuR0RQLlBDQVAuUFAuS0QpXQoKLSAgIERlc2NyaXB0aW9uOiBHRFAgcGVyIGNhcGl0YSBiYXNlZCBvbiBwdXJjaGFzaW5nIHBvd2VyIHBhcml0eSAoUFBQKS4gUFBQIEdEUCBpcyBncm9zcyBkb21lc3RpYyBwcm9kdWN0IGNvbnZlcnRlZCB0byBpbnRlcm5hdGlvbmFsIGRvbGxhcnMgdXNpbmcgcHVyY2hhc2luZyBwb3dlciBwYXJpdHkgcmF0ZXMuIEFuIGludGVybmF0aW9uYWwgZG9sbGFyIGhhcyB0aGUgc2FtZSBwdXJjaGFzaW5nIHBvd2VyIG92ZXIgR0RQIGFzIHRoZSBVLlMuIGRvbGxhciBoYXMgaW4gdGhlIFVuaXRlZCBTdGF0ZXMuIEdEUCBhdCBwdXJjaGFzZXIncyBwcmljZXMgaXMgdGhlIHN1bSBvZiBncm9zcyB2YWx1ZSBhZGRlZCBieSBhbGwgcmVzaWRlbnQgcHJvZHVjZXJzIGluIHRoZSBjb3VudHJ5IHBsdXMgYW55IHByb2R1Y3QgdGF4ZXMgYW5kIG1pbnVzIGFueSBzdWJzaWRpZXMgbm90IGluY2x1ZGVkIGluIHRoZSB2YWx1ZSBvZiB0aGUgcHJvZHVjdHMuIEl0IGlzIGNhbGN1bGF0ZWQgd2l0aG91dCBtYWtpbmcgZGVkdWN0aW9ucyBmb3IgZGVwcmVjaWF0aW9uIG9mIGZhYnJpY2F0ZWQgYXNzZXRzIG9yIGZvciBkZXBsZXRpb24gYW5kIGRlZ3JhZGF0aW9uIG9mIG5hdHVyYWwgcmVzb3VyY2VzLiBEYXRhIGFyZSBpbiBjb25zdGFudCAyMDE3IGludGVybmF0aW9uYWwgZG9sbGFycy4KCiMjIyBTZXR1cAoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFdESSkKYGBgCgoqSWYgeW91IGRvIG5vdCBoYXZlIGB3ZGljYWNoZS5yZHNgIGluIHlvdXIgZGF0YSBmb2xkZXIsIHJ1biB0aGUgZm9sbG93aW5nIHR3byBjb2RlIGNodW5rcy4qCgpgYGB7ciB3ZGljYWNoZSwgZXZhbD1GQUxTRX0Kd2RpY2FjaGUgPC0gV0RJY2FjaGUoKQpgYGAKCmBgYHtyIHdyaXRld2RpY2FjaGUsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9CndyaXRlX3Jkcyh3ZGljYWNoZSwgImRhdGEvd2RpY2FjaGUucmRzIikKYGBgCgpgYGB7ciByZWFkd2RpY2FjaGUsIGVjaG89RkFMU0V9CndkaWNhY2hlIDwtIHJlYWRfcmRzKCJkYXRhL3dkaWNhY2hlLnJkcyIpCmBgYAoKIyMjIERlc2NyaXB0aW9uIG9mIGRhdGEKCipgV0RJc2VhcmNoYCB3aXRoIGBzaG9ydCA9IEZBTFNFYCBwcm92aWRlcyB3aXRoIHRoZSBkZXNjcmlwdGlvbiBvZiBkYXRhIGluIHRoZSBsYXN0IGNvbHVtbi4qCgpgYGB7cn0KV0RJc2VhcmNoKHN0cmluZyA9ICJFTi5BVE0uQ08yRS5QQyIsIGZpZWxkID0gImluZGljYXRvciIsIAogICAgICAgICAgc2hvcnQgPSBGQUxTRSwgY2FjaGUgPSB3ZGljYWNoZSkKYGBgCgoqKkRlc2NyaXB0aW9uOioqIENhcmJvbiBkaW94aWRlIGVtaXNzaW9ucyBhcmUgdGhvc2Ugc3RlbW1pbmcgZnJvbSB0aGUgYnVybmluZyBvZiBmb3NzaWwgZnVlbHMgYW5kIHRoZSBtYW51ZmFjdHVyZSBvZiBjZW1lbnQuIFRoZXkgaW5jbHVkZSBjYXJib24gZGlveGlkZSBwcm9kdWNlZCBkdXJpbmcgY29uc3VtcHRpb24gb2Ygc29saWQsIGxpcXVpZCwgYW5kIGdhcyBmdWVscyBhbmQgZ2FzIGZsYXJpbmcuCgpgYGB7cn0KV0RJc2VhcmNoKHN0cmluZyA9ICJOWS5HRFAuUENBUC5QUC5LRCIsIGZpZWxkID0gImluZGljYXRvciIsIAogICAgICAgICAgc2hvcnQgPSBGQUxTRSwgY2FjaGUgPSB3ZGljYWNoZSkKYGBgCgoqKkRlc2NyaXRwdGlvbjoqKiBHRFAgcGVyIGNhcGl0YSBiYXNlZCBvbiBwdXJjaGFzaW5nIHBvd2VyIHBhcml0eSAoUFBQKS4gUFBQIEdEUCBpcyBncm9zcyBkb21lc3RpYyBwcm9kdWN0IGNvbnZlcnRlZCB0byBpbnRlcm5hdGlvbmFsIGRvbGxhcnMgdXNpbmcgcHVyY2hhc2luZyBwb3dlciBwYXJpdHkgcmF0ZXMuIEFuIGludGVybmF0aW9uYWwgZG9sbGFyIGhhcyB0aGUgc2FtZSBwdXJjaGFzaW5nIHBvd2VyIG92ZXIgR0RQIGFzIHRoZSBVLlMuIGRvbGxhciBoYXMgaW4gdGhlIFVuaXRlZCBTdGF0ZXMuIEdEUCBhdCBwdXJjaGFzZXIncyBwcmljZXMgaXMgdGhlIHN1bSBvZiBncm9zcyB2YWx1ZSBhZGRlZCBieSBhbGwgcmVzaWRlbnQgcHJvZHVjZXJzIGluIHRoZSBjb3VudHJ5IHBsdXMgYW55IHByb2R1Y3QgdGF4ZXMgYW5kIG1pbnVzIGFueSBzdWJzaWRpZXMgbm90IGluY2x1ZGVkIGluIHRoZSB2YWx1ZSBvZiB0aGUgcHJvZHVjdHMuIEl0IGlzIGNhbGN1bGF0ZWQgd2l0aG91dCBtYWtpbmcgZGVkdWN0aW9ucyBmb3IgZGVwcmVjaWF0aW9uIG9mIGZhYnJpY2F0ZWQgYXNzZXRzIG9yIGZvciBkZXBsZXRpb24gYW5kIGRlZ3JhZGF0aW9uIG9mIG5hdHVyYWwgcmVzb3VyY2VzLiBEYXRhIGFyZSBpbiBjb25zdGFudCAyMDE3IGludGVybmF0aW9uYWwgZG9sbGFycy4KCiMjIyBJbXBvcnRpbmcgYW5kIHNhdmluZyBkYXRhCgoqRm9yIGV4dHJhIGluZm9ybWF0aW9uIHdpdGggYGV4dHJhID0gVFJVRWAsIHdlIHByb3ZpZGUgdXBkYXRlZCBpbmZvcm1hdGlvbiB3aXRoIGBjYWNoZSA9IHdkaWNhY2hlYC4qCgpgYGB7ciBjYWNoZSA9IFRSVUUsIGV2YWwgPSBGQUxTRX0KZGZfY28yZ2RwIDwtIFdESShpbmRpY2F0b3IgPSBjKGNvMnBjYXAgPSAiRU4uQVRNLkNPMkUuUEMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdkcHBjYXAgPSAiTlkuR0RQLlBDQVAuUFAuS0QiKSwKICAgICAgICAgICAgICAgICBleHRyYSA9IFRSVUUsIGNhY2hlID0gd2RpY2FjaGUpCmBgYAoKYGBge3IgZXZhbCA9IEZBTFNFfQp3cml0ZV9jc3YoZGZfY28yZ2RwLCAiZGF0YS9jbzJnZHAuY3N2IikKYGBgCgpgYGB7cn0KZGZfY28yZ2RwIDwtIHJlYWRfY3N2KCJkYXRhL2NvMmdkcC5jc3YiKQpgYGAKCiMjIyBWaWV3aW5nIGFuZCBjaGVja2luZyB0aGUgZGF0YQoKKlRocmVlIHdheXMgdG8gbG9vayBhdCB0aGUgdGFibGUuIGBkZl9jbzJnZHBgICwgYGhlYWQoZGZfY28yZ2RwKWAgLCBkZl9jbzJnZHAgdW5kZXIgRW52aXJvbm1lbnQgdGFiIGluIHRoZSB0b3AgcmlnaHQgcGFuZS4qCgpgYGB7cn0KZGZfY28yZ2RwCmBgYAoKKklmIHlvdSBkbyBub3QgYWRkIGBjYWNoZSA9IHdkaWNhY2hlYCB3aGVuIHlvdSBkb3dubG9hZCBkYXRhIHdpdGggYGV4dHJhID0gVFJVRWAsIHJlZ2lvbiBhbmQgaW5jb21lIG9mIHRoZXNlIGNvdW50cmllcyB3b3VsZCBiZSBOQSBhcyB0aGUgY291bnRyeSBpbmZvcm1hdGlvbiBhdHRhY2hlZCB0byB0aGUgcGFja2FnZSByZXF1aXJlcyB1cGRhdGUgdXNpbmcgYFdESWNhY2hlKCkuYCogKkFzIGZvciBDemVjaGlhIGFuZCBWaWV0IE5hbSwgc2VlIHRoZSBmaWxlIFtbTGlua10oaHR0cHM6Ly9kcy1zbC5naXRodWIuaW8vaW50cm8yci9kYTRyL2xpZmVfZXhwZWN0YW5jeS5uYi5odG1sKV0gYW5kIGl0cyBBZGRlbmR1bS4qCgpgYGB7cn0KZGZfY28yZ2RwIHw+IGZpbHRlcihjb3VudHJ5ICVpbiUgYygiQ3plY2hpYSIsICJWaWV0IE5hbSIpKSB8PgogIGRpc3RpbmN0KGNvdW50cnksIHJlZ2lvbiwgaW5jb21lKQpgYGAKCiMjIyMgU3RydWN0dXJlIG9mIGRhdGEKCmBnbGltcHNlKGRmX2NvMmdkcClgIGRvZXMgYWJvdXQgdGhlIHNhbWUuCgpgYGB7cn0Kc3RyKGRmX2NvMmdkcCkKYGBgCgojIyMjIFNlbGVjdCBjb2x1bW5zCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCA8LSBkZl9jbzJnZHAgfD4gc2VsZWN0KGNvdW50cnksIGlzbzJjLCB5ZWFyLCBjbzJwY2FwLCBnZHBwY2FwLCByZWdpb24sIGluY29tZSkKYGBgCgoqQ2hlY2sgdGhlIGRpc3RpbmN0IHJlZ2lvbiBuYW1lcyB1bmRlciB0aGUgY29sdW1uIHJlZ2lvbiBvciBpbmNvbWUuKgoKYGBge3J9CnVuaXF1ZShkZl9jbzJnZHBwY2FwJHJlZ2lvbikKYGBgCgoqVGhlIGZvbGxvd2luZyBkb2VzIHRoZSBzYW1lLioKCmBgYHtyfQpkZl9jbzJnZHBwY2FwIHw+IGRpc3RpbmN0KHJlZ2lvbikgfD4gcHVsbCgpCmBgYAoKKlVzaW5nIGRwdXQoKSBtYXkgYmUgaGFuZHkgaWYgeW91IHdhbnQgdG8gdXNlIHRoZSBvdXRwdXQuKgoKYGBge3J9CnVuaXF1ZShkZl9jbzJnZHBwY2FwJGluY29tZSkgfD4gZHB1dCgpCmBgYAoKYGBge3J9CklOQ09NRSA8LWMoIkxvdyBpbmNvbWUiLCAiTG93ZXIgbWlkZGxlIGluY29tZSIsICJVcHBlciBtaWRkbGUgaW5jb21lIiwgCiJIaWdoIGluY29tZSIpCmBgYAoKKkl0IGlzIHBvc3NpYmxlIHRvIGdldCB0aGUgaW5mb3JtYXRpb24gaW4gb25lIGNvZGUgY2h1bmsuKgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gc2VsZWN0KHJlZ2lvbiwgaW5jb21lKSB8PiBsYXBwbHkodW5pcXVlKQpgYGAKCiMjIyBSZWdpb25zIGFuZCBDb3VudHJpZXMKCipJdCBpcyBjb252ZW5pZW50IHRvIGhhdmUgYSBsaXN0IGF0IGhhbmQuKgoKYGBge3J9CndkaWNhY2hlJGNvdW50cnkgfD4gZmlsdGVyKHJlZ2lvbiA9PSAiQWdncmVnYXRlcyIpIHw+IAogIGRpc3RpbmN0KGNvdW50cnksIGlzbzJjKSAKYGBgCgoqQ29tcGFyZSB0aGUgZm9sbG93aW5nIHdpdGggYWJvdmUuKgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHJlZ2lvbiA9PSAiQWdncmVnYXRlcyIpIHw+IAogIGRpc3RpbmN0KGNvdW50cnksIGlzbzJjKSAKYGBgCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoaXMubmEocmVnaW9uKSkgfD4gCiAgZGlzdGluY3QoY291bnRyeSwgaXNvMmMpIApgYGAKCiMjIyBDb3VudHJpZXMKCmBgYHtyfQp3ZGljYWNoZSRjb3VudHJ5IHw+IGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiAKICBkaXN0aW5jdChjb3VudHJ5LCBpc28yYywgcmVnaW9uLCBpbmNvbWUpIHw+IGFycmFuZ2UoY291bnRyeSkKYGBgCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZGlzdGluY3QoY291bnRyeSwgaXNvMmMsIHJlZ2lvbiwgaW5jb21lKSB8PiBhcnJhbmdlKGNvdW50cnkpCmBgYAoKT2JzZXJ2YXRpb25zOgoKLSAgIEhvdyBjYW4gd2UgZ2V0IHRoZSBkaWZmZXJlbmNlIGVhc2lseT8KCiMjIyBOdW1iZXIgb2YgZGF0YSBvZiBlYWNoIHllYXIKCipDaGVjayB3aGV0aGVyIHlvdSBoYXZlIGVub3VnaCBkYXRhIGluIGVhY2ggeWVhci4qCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBkcm9wX25hKGNvMnBjYXAsIGdkcHBjYXApIHw+CiAgZ2dwbG90KGFlcyh5ZWFyKSkgKyBnZW9tX2JhcigpCmBgYAoKT2JzZXJ2YXRpb246CgotICAgVGhlIGRhdGEgc3RhcnRzIGluIHRoZSB5ZWFyIDE5OTAgYW5kIGVuZHMgaW4gMjAyMC4gVGhlcmUgYXJlIGRhdGEgb2Ygb3ZlciAyMDAgY291bnRyaWVzIGFuZCByZWdpb25zLgoKVGhlIGNvZGUgYWJvdmUgaXMgc2FtZSBhcyB0aGUgZm9sbG93aW5nLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZHJvcF9uYShjbzJwY2FwLCBnZHBwY2FwKSB8PgogIGdyb3VwX2J5KHllYXIpIHw+IHN1bW1hcml6ZShuID0gbigpKSB8PgogIGdncGxvdChhZXMoeWVhciwgbikpICsgZ2VvbV9jb2woKQpgYGAKCiMjIyBWaXN1YWxpemF0aW9uIGJ5IExpbmUgR3JhcGhzCgojIyMjIENPfjJ+IHBlciBjYXBpdGEKCmBgYHtyfQpDT1VOVFJZIDwtICJXb3JsZCIKZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoY291bnRyeSA9PSBDT1VOVFJZKSB8PiBkcm9wX25hKGNvMnBjYXApIHw+CiAgZ2dwbG90KGFlcyh5ZWFyLCBjbzJwY2FwKSkgKyBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9IGV4cHJlc3Npb24ocGFzdGUoQ09bMl0sICIgcGVyIGNhcGl0YSBvZiB0aGUgV29ybGQiKSksCiAgICAgICB5ID0gZXhwcmVzc2lvbihwYXN0ZShDT1syXSwgIiBwZXIgY2FwaXRhIGluIHRvbnMiKSkpCmBgYAoKT2JzZXJ2YXRpb25zOgoKLSAgIENPMiBwZXIgY2FwaXRhIG9mIHRoZSBXb3JsZCBpcyBkZWNyZWFzaW5nIGJ1dCBub3QgbXVjaC4KCmBgYHtyfQpJU08yQyA8LSBjKCJKUCIsICJDTiIsICJJRCIsICJHQiIsICJVUyIsICJERSIsICJGUiIpCmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKGlzbzJjICVpbiUgSVNPMkMpIHw+IGRyb3BfbmEoY28ycGNhcCkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIGNvMnBjYXAsIGNvbCA9IGlzbzJjKSkgKyBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9IGV4cHJlc3Npb24ocGFzdGUoQ09bMl0sICIgcGVyIGNhcGl0YSBvZiBzZXZlbiBjb251dHJpZXMgd2l0aCBsYXJnZSBHRFAiKSksCiAgICAgICBzdWJ0aXRsZSA9ICJDaGluYSwgR2VybWFueSwgRnJhbmNlLCBVbml0ZWQgS2luZ2RvbSwgSW5kaWEsIEphcGFuLCBVbml0ZWQgU3RhdGVzIiwgCiAgICAgICB5ID0gZXhwcmVzc2lvbihwYXN0ZShDT1syXSwgIiBwZXIgY2FwaXRhIGluIHRvbnMiKSkpCmBgYAoKT2JzZXJ2YXRpb25zOgoKLSAgIE5lZWQgdG8gc3R1ZHkgbW9yZSBpbiBkZXRhaWwuCgojIyMjIEdEUCBwZXIgY2FwaXRhCgpgYGB7cn0KQ09VTlRSWSA8LSAiV29ybGQiCmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4gZHJvcF9uYShnZHBwY2FwKSB8PgogIGdncGxvdChhZXMoeWVhciwgZ2RwcGNhcCkpICsgZ2VvbV9saW5lKCkgKwogIGxhYnModGl0bGUgPSAiR0RQIHBlciBjYXBpdGEgb2YgdGhlIFdvcmxkIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgVGhlcmUgYXJlIHR3byBkcm9wcyBidXQgaW5jcmVhc2luZyBzdGVhZGlseS4KCmBgYHtyfQpJU08yQyA8LSBjKCJKUCIsICJDTiIsICJJRCIsICJHQiIsICJVUyIsICJERSIsICJGUiIpCmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKGlzbzJjICVpbiUgSVNPMkMpIHw+IGRyb3BfbmEoZ2RwcGNhcCkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIGdkcHBjYXAsIGNvbCA9IGlzbzJjKSkgKyBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJHRFAgcGVyIGNhcGl0YSBvZiBzZXZlbiBjb3VudHJpZXMgd2l0aCBsYXJnZSBHRFAiLAogICAgICAgc3VidGl0bGUgPSAiQ2hpbmEsIEdlcm1hbnksIEZyYW5jZSwgVW5pdGVkIEtpbmdkb20sIEluZGlhLCBKYXBhbiwgVW5pdGVkIFN0YXRlcyIsIAogICAgICAgeSA9ICJHRFAgcGVyIGNhcGl0YSBQUFAiLAogICAgICAgY2FwdGlvbiA9ICJjb25zdGFudCAyMDE3IGludGVybmF0aW9uYWwgdXNkIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgTmVlZCB0byBzdHVkeSBlYWNoIGluIGRldGFpbC4KCiMjIyMgUmFua2luZyBvZiBDT34yfiBwZXIgY2FwaXRhCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4KICBkcm9wX25hKGNvMnBjYXApIHw+IGFycmFuZ2UoZGVzYyhjbzJwY2FwKSkKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgTWFueSBvaWwgcHJvZHVjaW5nIGNvdW50cmllcyBhcmUgb24gdGhlIHRvcC4KCmBgYHtyfQpkZl9jbzJnZHBwY2FwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PgogIGRyb3BfbmEoY28ycGNhcCkgfD4gYXJyYW5nZShjbzJwY2FwKQpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gICBUb3AgMTAgY291bnRyaWVzIG9mIENPfjJ+IGVtaXNzaW9uIHBlciBjYXBpdGE6CgogICAgLSAgIFF0YXIsIEJhaHJhaW4sIEJydW5laSBEYXJ1c3NhbGFtLCBLdXdhaXQsIFVuaXRlZCBBcmFiIEVtaXJhdGVzLCBPbWFuLCBBdXN0cmFsaWEsIFNhdWRpIEFyYWJpYSwgQ2FuYWRhLCBhbmQgVW5pdGVkIFN0YXRlcwoKLSAgIExvd2VzdCAxMCBjb3VudHJpZXMgb2YgQ09+Mn4gZW1pc3Npb24gcGVyIGNhcGl0YToKCiAgICAtICAgQ29uZ28sIERlbS4gUmVwLiwgU29tYWxpYSwgQ2VudHJhbCBBZnJpY2FuIFJlcHVibGljLCBCdXJ1bmRpLCBNYWxhd2ksIE5pZ2VyLCBDaGFkLCBNYWRhZ2FzY2FyLCBSd2FuZGEsIFNpZXJyYSBMZW9uZQoKLSAgIFRoZSB0b3AgMTAgaXMgYWJvdXQgMTAwMCB0aW1lcyB0aGUgYm90dG9tIDEwLgoKIyMjIyBSYW5raW5nIG9mIEdEUCBwZXIgY2FwaXRhCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiAKICBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4KICBkcm9wX25hKGdkcHBjYXApIHw+IGFycmFuZ2UoZGVzYyhnZHBwY2FwKSkKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgSW50ZXJlc3RpbmcuIEkga25vdyB0aGUgcmFua2luZyBvZiBHRFAgYnV0IG5vdCBHRFAgcGVyIGNhcGl0YS4KCmBgYHtyfQpkZl9jbzJnZHBwY2FwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IAogIGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PgogIGRyb3BfbmEoZ2RwcGNhcCkgfD4gYXJyYW5nZShnZHBwY2FwKQpgYGAKCk9ic2VydmF0aW9uczoKCi0gICBUb3AgMTAgaXMgYWJvdXQgMTAwIHRpbWVzIHRoZSBib3R0b20gMTAuCgojIyMgSGlzdG9ncmFtcyBhbmQgQm94cGxvdHMgZm9yIFZhcmlhdGlvbgoKIyMjIyBDT34yfiBwZXIgY2FwaXRhCgoqQ2hhbmdlIHRoZSBiaW5zIG9yIGJpbndpZHRoLioKCmBgYHtyfQpkZl9jbzJnZHBwY2FwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IAogIGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiBkcm9wX25hKGNvMnBjYXApIHw+IAogIGdncGxvdChhZXMoY28ycGNhcCkpICsgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCmBgYHtyfQpkZl9jbzJnZHBwY2FwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IAogIGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiBkcm9wX25hKGNvMnBjYXApIHw+IAogIGdncGxvdChhZXMoY28ycGNhcCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDEwKQpgYGAKCk9ic2VydmF0aW9uczoKCi0gICBGb3IgbW9zdCBvZiB0aGUgY291bnRyaWVzLCB0aGUgdmFsdWUgaXMgbGVzcyB0aGFuIDUgdG9ucyBwZXIgcGVyc29uIHBlciB5ZWFyLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gCiAgZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+IGRyb3BfbmEoY28ycGNhcCkgfD4gCiAgZ2dwbG90KGFlcyhjbzJwY2FwLCBmaWxsID0gcmVnaW9uKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTUsIGNvbCA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuMikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgSW50ZXJlc3RpbmcgYnV0IGNvbXBsaWNhdGVkLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gCiAgZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+IGRyb3BfbmEoY28ycGNhcCkgfD4gCiAgZ2dwbG90KGFlcyhjbzJwY2FwLCBmaWxsID0gZmFjdG9yKGluY29tZSwgbGV2ZWxzID0gSU5DT01FKSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDE1LCBjb2wgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjIpICsKICBsYWJzKGZpbGwgPSAiIikKYGBgCgoqKk9ic2VydmF0aW9ucyBhbmQgUXVlc3Rpb25zOioqCgotICAgSGlnaCBpbmNvbWUgY291bnRyaWVzIGhhdmUgbGFyZ2VyIHZhbHVlcyBpbiBnZW5lcmFsLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+IAogIGRyb3BfbmEoY28ycGNhcCkgfD4gZmlsdGVyKGluY29tZSAhPSAiTm90IGNsYXNzaWZpZWQiKSB8PgogIGdncGxvdChhZXMoY28ycGNhcCwgZmlsbCA9IGZhY3RvcihpbmNvbWUsIGxldmVscyA9IElOQ09NRSkpKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNSwgY29sID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC4xKSArIAogIHNjYWxlX3hfbG9nMTAoKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgQ08yIHBlciBjYXBpdGEgaW4gMjAyMCIsIGZpbGwgPSAiIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgRWFjaCBvZiBsb2cxMCBzY2FsZSBhbmQgdGhlIHJhdyB2YWx1ZSBzZWVtcyB0byB0ZWxsIGRpZmZlcmVudCBmZWF0dXJlLgoKLSAgIE5lZWQgdG8gY29uc2lkZXIgTkEgdmFsdWUgaW4gaW5jb21lLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgJWluJSBjKDE5OTAsIDIwMDAsIDIwMTAsIDIwMjApKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShjbzJwY2FwKSB8PiBmaWx0ZXIoY28ycGNhcCA+IDApIHw+IGZpbHRlcihpbmNvbWUgIT0gIk5vdCBjbGFzc2lmaWVkIikgfD4gCiAgZ2dwbG90KGFlcyhjbzJwY2FwLCBmaWxsID0gZmFjdG9yKHllYXIpKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTUsIGNvbCA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuMSkgKyAKICBzY2FsZV94X2xvZzEwKCkgKyBmYWNldF93cmFwKH55ZWFyKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgQ08yIHBlciBjYXBpdGEgaW4gMTk5MCwgMjAwMCwgMjAxMCwgMjAyMCIsIGZpbGwgPSAiIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgV2FudCBvbGQgZGF0YSwgYnV0IGNhbiBzZWUgZGlmZmVyZW5jZXMuCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoeWVhciAlaW4lIGMoMTk5MCwgMjAwMCwgMjAxMCwgMjAyMCkpIHw+IGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiAKICBkcm9wX25hKGNvMnBjYXApIHw+IGZpbHRlcihjbzJwY2FwID4gMCkgfD4gZmlsdGVyKGluY29tZSAhPSAiTm90IGNsYXNzaWZpZWQiKSB8PiAKICBnZ3Bsb3QoYWVzKGNvMnBjYXAsIGZhY3Rvcih5ZWFyKSwgZmlsbCA9IGZhY3Rvcih5ZWFyKSkpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyBzY2FsZV94X2xvZzEwKCkgKyBsYWJzKHkgPSAiIikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKT2JzZXJ2YXRpb25zOgoKLSAgIE5vdCBtdWNoIGRpZmZlcmVudCBidXQgdGhlIHdpZHRoIGlzIGRlY3JlYXNpbmcuCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShjbzJwY2FwKSB8PiBmaWx0ZXIoY28ycGNhcCA+IDApIHw+IGZpbHRlcihpbmNvbWUgIT0gIk5vdCBjbGFzc2lmaWVkIikgfD4gCiAgZ2dwbG90KGFlcyhjbzJwY2FwLCBmYWN0b3IoaW5jb21lLCBsZXZlbHMgPSBJTkNPTUUpLCBmaWxsID0gaW5jb21lKSkgKyAKICBnZW9tX2JveHBsb3QoKSArIHNjYWxlX3hfbG9nMTAoKSArIAogIGxhYnModGl0bGUgPSAiQ08yIHBlciBjYXBpdGEgYnkgaW5jb21lIGxldmVsIiwgeSA9ICIiLCBmaWxsID0gIiIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKT2JzZXJ2YXRpb25zOgoKLSAgIFRoZSByZXN1bHQgbG9va3MgbmF0dXJhbC4gSG93ZXZlciwgaXQgaXMgd29ydGggYW5hbHlzaW5nIG91dGxpZXJzIGluIGRldGFpbC4KCmBgYHtyfQpkZl9jbzJnZHBwY2FwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiAKICBkcm9wX25hKGNvMnBjYXApIHw+IGZpbHRlcihjbzJwY2FwID4gMCkgfD4gCiAgZ2dwbG90KGFlcyhjbzJwY2FwLCByZWdpb24sIGZpbGwgPSByZWdpb24pKSArIAogIGdlb21fYm94cGxvdCgpICsgc2NhbGVfeF9sb2cxMCgpICsgCiAgbGFicyh0aXRsZSA9ICJDTzIgcGVyIGNhcGl0YSBieSByZWdpb24iLCB5ID0gIiIsIGZpbGwgPSAiIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgTmVlZCB0byBpbnZlc3RpZ2F0ZSBlYWNoIHJlZ2lvbiBjbG9zZWx5LgoKIyMjIyBHRFAgcGVyIGNhcGl0YQoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gCiAgZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIsICFpcy5uYShpbmNvbWUpKSB8PgogIGRyb3BfbmEoZ2RwcGNhcCkgfD4gZ2dwbG90KGFlcyhnZHBwY2FwLCBmYWN0b3IoaW5jb21lLCBsZXZlbHMgPSBJTkNPTUUpLCBmaWxsID0gaW5jb21lKSkgKyBnZW9tX2JveHBsb3QoKSArIHNjYWxlX3hfbG9nMTAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBsYWJzKHkgPSAiIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgVGhlcmUgYXJlIG92ZXJsYXBzLiBOZWVkIHRvIHN0dWR5IGhvdyB0aGUgaW5jb21lIGxldmVsIGlzIGRldGVybWluZWQgYnkgV29ybGQgQmFuay4KCiAgICAtICAgSG93IGRvZXMgdGhlIFdvcmxkIEJhbmsgY2xhc3NpZnkgY291bnRyaWVzPyBbW0xpbmtdKGh0dHBzOi8vZGF0YWhlbHBkZXNrLndvcmxkYmFuay5vcmcva25vd2xlZGdlYmFzZS9hcnRpY2xlcy8zNzg4MzQtaG93LWRvZXMtdGhlLXdvcmxkLWJhbmstY2xhc3NpZnktY291bnRyaWVzKV0KCmBgYHtyfQpkZl9jbzJnZHBwY2FwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IAogIGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiLCAhaXMubmEocmVnaW9uKSkgfD4KICBkcm9wX25hKGdkcHBjYXApIHw+CiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBmaWxsID0gcmVnaW9uKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTUsIGNvbCA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuMikgKyAKICBsYWJzKGZpbGwgPSAiIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgSW50ZXJlc3RpbmcgYnV0IGNvbXBsaWNhdGVkLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gCiAgZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIsICFpcy5uYShyZWdpb24pKSB8PgogIGRyb3BfbmEoZ2RwcGNhcCkgfD4KICBnZ3Bsb3QoYWVzKGdkcHBjYXAsIGZpbGwgPSByZWdpb24pKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNSwgY29sID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC4yKSArIHNjYWxlX3hfbG9nMTAoKSArCiAgbGFicyhmaWxsID0gIiIpCmBgYAoKT2JzZXJ2YXRpb25zOgoKLSAgIFR3byBzY2FsZXMgZ2l2ZSBkaWZmZXJlbnQgaW5mb3JtYXRpb24gYW5kIGltcHJlc3Npb24uCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShnZHBwY2FwKSB8PiBmaWx0ZXIoaW5jb21lICE9ICJOb3QgY2xhc3NpZmllZCIpIHw+CiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBmaWxsID0gZmFjdG9yKGluY29tZSwgbGV2ZWxzID0gSU5DT01FKSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDE1LCBjb2wgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjEpICsgCiAgc2NhbGVfeF9sb2cxMCgpICsKICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBHRFAgcGVyIGNhcGl0YSBpbiAyMDIwIiwgZmlsbCA9ICIiKQpgYGAKCk9ic2VydmF0aW9uczoKCi0gICBOZWVkIHRvIHN0dWR5IG92ZXJsYXBzLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgJWluJSBjKDE5OTAsIDIwMDAsIDIwMTAsIDIwMjApKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShnZHBwY2FwKSB8PiBmaWx0ZXIoZ2RwcGNhcCA+IDApIHw+IGZpbHRlcihpbmNvbWUgIT0gIk5vdCBjbGFzc2lmaWVkIikgfD4gCiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBmaWxsID0gZmFjdG9yKHllYXIpKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTUsIGNvbCA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuMSkgKyAKICBzY2FsZV94X2xvZzEwKCkgKyBmYWNldF93cmFwKH55ZWFyKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgR0RQIHBlciBjYXBpdGEgaW4gMTk5MCwgMjAwMCwgMjAxMCwgMjAyMCIsIGZpbGwgPSAiIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgQ2Fubm90IHNlZSBhIGJpZyBkaWZmZXJlbmNlLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgJWluJSBjKDE5OTAsIDIwMDAsIDIwMTAsIDIwMjApKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShnZHBwY2FwKSB8PiBmaWx0ZXIoZ2RwcGNhcCA+IDApIHw+IGZpbHRlcihpbmNvbWUgIT0gIk5vdCBjbGFzc2lmaWVkIikgfD4gCiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBmYWN0b3IoeWVhciksIGZpbGwgPSBmYWN0b3IoeWVhcikpKSArIAogIGdlb21fYm94cGxvdCgpICsgc2NhbGVfeF9sb2cxMCgpICsgbGFicyh5ID0gIiIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCk9ic2VydmF0aW9uczoKCi0gICBOb3QgbXVjaCBjYW4gYmUgc2Vlbi4KCmBgYHtyfQpkZl9jbzJnZHBwY2FwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiAKICBkcm9wX25hKGdkcHBjYXApIHw+IGZpbHRlcihnZHBwY2FwID4gMCkgfD4gZmlsdGVyKGluY29tZSAhPSAiTm90IGNsYXNzaWZpZWQiKSB8PiAKICBnZ3Bsb3QoYWVzKGdkcHBjYXAsIGZhY3RvcihpbmNvbWUsIGxldmVscyA9IElOQ09NRSksIGZpbGwgPSBpbmNvbWUpKSArIAogIGdlb21fYm94cGxvdCgpICsgc2NhbGVfeF9sb2cxMCgpICsgCiAgbGFicyh0aXRsZSA9ICJHRFAgcGVyIGNhcGl0YSBieSBpbmNvbWUgbGV2ZWwiLCB5ID0gIiIsIGZpbGwgPSAiIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgQ2FuIHNlZSBhIHRyZW5kLgoKYGBge3J9CmRmX2NvMmdkcHBjYXAgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+IAogIGRyb3BfbmEoZ2RwcGNhcCkgfD4gZmlsdGVyKGdkcHBjYXAgPiAwKSB8PiAKICBnZ3Bsb3QoYWVzKGdkcHBjYXAsIHJlZ2lvbiwgZmlsbCA9IHJlZ2lvbikpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyBzY2FsZV94X2xvZzEwKCkgKyAKICBsYWJzKHRpdGxlID0gIkdEUCBwZXIgY2FwaXRhIGJ5IHJlZ2lvbiIsIHkgPSAiIiwgZmlsbCA9ICIiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCk9ic2VydmF0aW9uczoKCi0gICBXaGF0IGlzIHRoZSBiZXN0IHdheSB0byBsb29rIGF0IHJlZ2lvbmFsIGRpZmZlcmVuY2VzPwoKIyMjIFNjYXR0ZXJwbG90IGZvciBDb3ZhcmlhdGlvbgoKIyMjIyBTY2F0dGVycGxvdCB3aXRoIGEgcmVncmVzc2lvbiBsaW5lCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiAKICBkcm9wX25hKGdkcHBjYXAsIGNvMnBjYXApIHw+CiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBjbzJwY2FwKSkgKyBnZW9tX3BvaW50KGFlcyhjb2wgPSByZWdpb24pKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9ICd5fngnLCBzZSA9IEZBTFNFKSArCiAgc2NhbGVfeF9sb2cxMCgpICsgc2NhbGVfeV9sb2cxMCgpICsKICBsYWJzKHRpdGxlID0gIkdEUCBwZXIgY2FwaXRhIHZzIENPMiBwZXIgY2FwaXRhIiwKICAgICAgIHggPSAiR0RQIHBlciBjYXBpdGEiLAogICAgICAgeSA9IGV4cHJlc3Npb24ocGFzdGUoQ09bMl0sICIgcGVyIGNhcGl0YSBpbiB0b25zIikpKQpgYGAKCk9ic2VydmF0aW9uczoKCi0gICBHRFAgcGVyIGNhcGl0YSBpbiBsb2cxMCBzY2FsZSBhbmQgQ28yIHBlciBjYXBpdGEgcmVsYXRlcyBwb3NpdGl2ZWx5IGFuZCB0aGUgcmVncmVzc2lvbiBsaW5lIGxvb2tzIHdlbGwtZml0LgoKIyMjIyBTdW1tYXJ5IG9mIGEgbGluZWFyIG1vZGVsCgoqWW91IHdpbGwgbGVhcm4gaG93IHRvIGludGVycHJldGUgdGhlIHZhbHVlcyBiZWxvdyBsYXRlciBpbiB0aGlzIGNvdXJzZS4qCgpgYGB7cn0KZGZfY28yZ2RwcGNhcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBkcm9wX25hKGdkcHBjYXAsIGNvMnBjYXApIHw+CiAgbG0obG9nMTAoY28ycGNhcCl+bG9nMTAoZ2RwcGNhcCksIGRhdGEgPSBfKSB8PiBzdW1tYXJ5KCkKYGBgCgpPYnNlcnZhdGlvbnM6CgotICAgSW4gbG9nMTAgc2NhbGUsIHRoZSByZWdyZXNzaW9uIGxpbmUgZml0cyB3ZWxsIHdpdGggc2xvcGUgMS4xLgoKLSAgIE11bHRpcGxlIFItc3F1YXJlIGlzIDAuODQgYW5kIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBleHBsYWlucyBnb29kIHBhcnQgb2YgdGhlIHJlbGF0aW9uIG9mIHRoZXNlIGRhdGEuCgojIFlvdXIgUHJvamVjdAoKIyMgVGl0bGUgb2YgeW91ciBwcm9qZWN0CgpXZSBzdHVkeSAuLi4uLgoKMS4gIE5hbWUgb2YgdGhlIGluZGljYXRvciAxOiBJbmRpY2F0b3IgQ29kZSAxCgotICAgRGVzY3JpcHRpb246CgoyLiAgTmFtZSBvZiB0aGUgaW5kaWNhdG9yIDI6IEluZGljYXRvciBDb2RlIDIKCi0gICBEZXNjcmlwdGlvbjoKCiMjIyBJbXBvcnRpbmcgRGF0YQoKYGBgez1odG1sfQo8c3BhbiBzdHlsZSA9ICJjb2xvcjogcmVkOyI+RWRpdCB0aGUgZm9sbG93aW5nIGNvZGUgY2h1bmshPC9zcGFuPgpgYGAKYGBge3J9CmNob3Nlbl9pbmRpY2F0b3JfMSA8LSAiU0UuU0VDLkVOUlIiICNleGFtcGxlCnNob3J0X25hbWVfMSA8LSAic2VjIgpjaG9zZW5faW5kaWNhdG9yXzIgPC0gIk5ZLkdEUC5QQ0FQLlBQLktEIiAjZXhhbXBsZQpzaG9ydF9uYW1lXzIgPC0gImdkcHBjYXAiCmBgYAoKYGBge3IgY2FjaGUgPSBUUlVFfQpkZl95b3VyZGF0YSA8LSBXREkoaW5kaWNhdG9yID0gYyhzaG9ydF9uYW1lXzEgPSBjaG9zZW5faW5kaWNhdG9yXzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3J0X25hbWVfMiA9IGNob3Nlbl9pbmRpY2F0b3JfMiksCiAgICAgICAgICAgICAgICAgZXh0cmEgPSBUUlVFLCBjYWNoZSA9IHdkaWNhY2hlKQpgYGAKCmBgYHtyfQp3cml0ZV9jc3YoZGZfeW91cmRhdGEsICJkYXRhL3lvdXJkYXRhLmNzdiIpCmBgYAoKYGBge3J9CmRmX3lvdXJkYXRhIDwtIHJlYWRfY3N2KCJkYXRhL3lvdXJkYXRhLmNzdiIpCmBgYAoKIyMjIFZpc3VhbGl6YXRpb24gYnkgTGluZSBHcmFwaHMKCiMjIyMgTmFtZSBvZiB0aGUgSW5kaWNhdG9yIDEKCmBgYHs9aHRtbH0KPHNwYW4gc3R5bGUgPSAiY29sb3I6IHJlZDsiPkVkaXQgdGhlIHRpdGxlIGFuZCB0aGUgbGFiZWwgb2YgeS1heGlzLjwvc3Bhbj4KYGBgCmBgYHtyfQpDT1VOVFJZIDwtICJXb3JsZCIKZGZfeW91cmRhdGEgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4gZHJvcF9uYShzaG9ydF9uYW1lXzEpIHw+CiAgZ2dwbG90KGFlcyh5ZWFyLCBzaG9ydF9uYW1lXzEpKSArIGdlb21fbGluZSgpICsKICBsYWJzKHRpdGxlID0gIiIsCiAgICAgICB5ID0gIiIpCmBgYAoKKipPYnNlcnZhdGlvbnMgYW5kIFF1ZXN0aW9uczoqKgoKLSAgIAoKYGBgez1odG1sfQo8c3BhbiBzdHlsZSA9ICJjb2xvcjogcmVkOyI+RWRpdCBJU08yQywgdGl0bGUsIHN1YnRpdGxlLCBhbmQgdGhlIGxhYmVsIG9mIHktYXhpcy48L3NwYW4+CmBgYApgYGB7cn0KSVNPMkMgPC0gYygiSlAiLCAiQ04iLCAiSUQiLCAiR0IiLCAiVVMiLCAiREUiLCAiRlIiKQpkZl95b3VyZGF0YSB8PiBmaWx0ZXIoaXNvMmMgJWluJSBJU08yQykgfD4gZHJvcF9uYShzaG9ydF9uYW1lXzEpIHw+CiAgZ2dwbG90KGFlcyh5ZWFyLCBzaG9ydF9uYW1lXzEsIGNvbCA9IGlzbzJjKSkgKyBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICIiLAogICAgICAgc3VidGl0bGUgPSAiQ2hpbmEsIEdlcm1hbnksIEZyYW5jZSwgVW5pdGVkIEtpbmdkb20sIEluZGlhLCBKYXBhbiwgVW5pdGVkIFN0YXRlcyIsIAogICAgICAgeSA9ICIiKQpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gICAKCiMjIyMgTmFtZSBvZiB0aGUgSW5kaWNhdG9yIDIKCmBgYHs9aHRtbH0KPHNwYW4gc3R5bGUgPSAiY29sb3I6IHJlZDsiPkVkaXQgQ09VTlRSWSBhbmQgdGhlIHRpdGxlLjwvc3Bhbj4KYGBgCmBgYHtyfQpDT1VOVFJZIDwtICJXb3JsZCIKZGZfeW91cmRhdGEgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4gZHJvcF9uYShzaG9ydF9uYW1lXzIpIHw+CiAgZ2dwbG90KGFlcyh5ZWFyLCBzaG9ydF9uYW1lXzIpKSArIGdlb21fbGluZSgpICsKICBsYWJzKHRpdGxlID0gIiIpCmBgYAoKKipPYnNlcnZhdGlvbnMgYW5kIFF1ZXN0aW9uczoqKgoKLSAgIAoKYGBgez1odG1sfQo8c3BhbiBzdHlsZSA9ICJjb2xvcjogcmVkOyI+RWRpdCBJU08yQywgdGl0bGUsIHN1YnRpdGxlLCBhbmQgdGhlIGxhYmVsIG9mIHktYXhpcywgYW5kIGFkZCBjYXB0aW9uIGlmIHByZWZlcmFibGUuPC9zcGFuPgpgYGAKYGBge3J9CklTTzJDIDwtIGMoIkpQIiwgIkNOIiwgIklEIiwgIkdCIiwgIlVTIiwgIkRFIiwgIkZSIikKZGZfeW91cmRhdGEgfD4gZmlsdGVyKGlzbzJjICVpbiUgSVNPMkMpIHw+IGRyb3BfbmEoc2hvcnRfbmFtZV8yKSB8PgogIGdncGxvdChhZXMoeWVhciwgc2hvcnRfbmFtZV8yLCBjb2wgPSBpc28yYykpICsgZ2VvbV9saW5lKCkgKwogIGxhYnModGl0bGUgPSAiIiwKICAgICAgIHN1YnRpdGxlID0gIkNoaW5hLCBHZXJtYW55LCBGcmFuY2UsIFVuaXRlZCBLaW5nZG9tLCBJbmRpYSwgSmFwYW4sIFVuaXRlZCBTdGF0ZXMiLCAKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiIikKYGBgCgoqKk9ic2VydmF0aW9ucyBhbmQgUXVlc3Rpb25zOioqCgotICAgCgojIyMjIFJhbmtpbmcgb2YgdGhlIGluZGljYXRvciAxCgpgYGB7PWh0bWx9CjxzcGFuIHN0eWxlID0gImNvbG9yOiByZWQ7Ij5FZGl0IHllYXIgaWYgbmVjZXNzYXJ5Ljwvc3Bhbj4KYGBgCmBgYHtyfQpkZl95b3VyZGF0YSB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4KICBkcm9wX25hKHNob3J0X25hbWVfMSkgfD4gYXJyYW5nZShkZXNjKHNob3J0X25hbWVfMSkpCmBgYAoKYGBge3J9CmRmX3lvdXJkYXRhIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PgogIGRyb3BfbmEoc2hvcnRfbmFtZV8xKSB8PiBhcnJhbmdlKHNob3J0X25hbWVfMSkKYGBgCgoqKk9ic2VydmF0aW9ucyBhbmQgUXVlc3Rpb25zOioqCgotICAgCgojIyMjIFJhbmtpbmcgb2YgdGhlIEluZGljYXRvciAyCgpgYGB7cn0KZGZfeW91cmRhdGEgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+CiAgZHJvcF9uYShzaG9ydF9uYW1lXzIpIHw+IGFycmFuZ2UoZGVzYyhzaG9ydF9uYW1lXzIpKQpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gICAKCmBgYHtyfQpkZl95b3VyZGF0YSB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4KICBkcm9wX25hKHNob3J0X25hbWVfMikgfD4gYXJyYW5nZShzaG9ydF9uYW1lXzIpCmBgYAoKKipPYnNlcnZhdGlvbnMgYW5kIFF1ZXN0aW9uczoqKgoKLSAgIAoKIyMjIEhpc3RvZ3JhbXMgYW5kIEJveHBsb3RzIGZvciBWYXJpYXRpb24KCiMjIyMgTmFtZSBvZiB0aGUgSW5kaWNhdG9yIDEKCmBgYHs9aHRtbH0KPHNwYW4gc3R5bGUgPSAiY29sb3I6IHJlZDsiPkVkaXQgdGhlIHRpdGxlIGFuZCB5ZWFyLjwvc3Bhbj4KYGBgCmBgYHtyfQpkZl95b3VyZGF0YSB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShzaG9ydF9uYW1lXzEpIHw+IGZpbHRlcihpbmNvbWUgIT0gIk5vdCBjbGFzc2lmaWVkIikgfD4KICBnZ3Bsb3QoYWVzKHNob3J0X25hbWVfMSwgZmlsbCA9IGZhY3RvcihpbmNvbWUsIGxldmVscyA9IElOQ09NRSkpKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNSwgY29sID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC4xKSArIAogIHNjYWxlX3hfbG9nMTAoKSArCiAgbGFicyh0aXRsZSA9ICIiLCBmaWxsID0gIiIpCmBgYAoKKipPYnNlcnZhdGlvbnMgYW5kIFF1ZXN0aW9uczoqKgoKLSAgIAoKYGBgez1odG1sfQo8c3BhbiBzdHlsZSA9ICJjb2xvcjogcmVkOyI+RWRpdCB0aGUgdGl0bGUgYW5kIHRoZSB5ZWFycy48L3NwYW4+CmBgYApgYGB7cn0KZGZfeW91cmRhdGEgfD4gZmlsdGVyKHllYXIgJWluJSBjKDE5OTAsIDIwMDAsIDIwMTAsIDIwMjApKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShzaG9ydF9uYW1lXzEpIHw+IGZpbHRlcihzaG9ydF9uYW1lXzEgPiAwKSB8PiBmaWx0ZXIoaW5jb21lICE9ICJOb3QgY2xhc3NpZmllZCIpIHw+IAogIGdncGxvdChhZXMoc2hvcnRfbmFtZV8xLCBmaWxsID0gZmFjdG9yKHllYXIpKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTUsIGNvbCA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuMSkgKyAKICBzY2FsZV94X2xvZzEwKCkgKyBmYWNldF93cmFwKH55ZWFyKSArCiAgbGFicyh0aXRsZSA9ICIiLCBmaWxsID0gIiIpCmBgYAoKKipPYnNlcnZhdGlvbnMgYW5kIFF1ZXN0aW9uczoqKgoKLSAgIAoKYGBge3J9CmRmX3lvdXJkYXRhIHw+IGZpbHRlcih5ZWFyICVpbiUgYygxOTkwLCAyMDAwLCAyMDEwLCAyMDIwKSkgfD4gZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+IAogIGRyb3BfbmEoc2hvcnRfbmFtZV8xKSB8PiBmaWx0ZXIoc2hvcnRfbmFtZV8xID4gMCkgfD4gZmlsdGVyKGluY29tZSAhPSAiTm90IGNsYXNzaWZpZWQiKSB8PiAKICBnZ3Bsb3QoYWVzKHNob3J0X25hbWVfMSwgZmFjdG9yKHllYXIpLCBmaWxsID0gZmFjdG9yKHllYXIpKSkgKyAKICBnZW9tX2JveHBsb3QoKSArIHNjYWxlX3hfbG9nMTAoKSArIGxhYnMoeSA9ICIiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgoqKk9ic2VydmF0aW9ucyBhbmQgUXVlc3Rpb25zOioqCgotICAgCgpgYGB7PWh0bWx9CjxzcGFuIHN0eWxlID0gImNvbG9yOiByZWQ7Ij5FZGl0IHRoZSB0aXRsZSwgYW5kIHRoZSB5ZWFyIGlmIG5lY2Vzc2FyeS48L3NwYW4+CmBgYApgYGB7cn0KZGZfeW91cmRhdGEgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+IAogIGRyb3BfbmEoc2hvcnRfbmFtZV8xKSB8PiBmaWx0ZXIoc2hvcnRfbmFtZV8xID4gMCkgfD4gZmlsdGVyKGluY29tZSAhPSAiTm90IGNsYXNzaWZpZWQiKSB8PiAKICBnZ3Bsb3QoYWVzKHNob3J0X25hbWVfMSwgZmFjdG9yKGluY29tZSwgbGV2ZWxzID0gSU5DT01FKSwgZmlsbCA9IGluY29tZSkpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyBzY2FsZV94X2xvZzEwKCkgKyAKICBsYWJzKHRpdGxlID0gIiIsIHkgPSAiIiwgZmlsbCA9ICIiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gICAKCmBgYHs9aHRtbH0KPHNwYW4gc3R5bGUgPSAiY29sb3I6IHJlZDsiPkVkaXQgdGhlIHRpdGxlIGFuZCB5ZWFyIGlmIG5lY2Vzc2FyeS48L3NwYW4+CmBgYApgYGB7cn0KZGZfeW91cmRhdGEgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+IAogIGRyb3BfbmEoc2hvcnRfbmFtZV8xKSB8PiBmaWx0ZXIoc2hvcnRfbmFtZV8xID4gMCkgfD4gCiAgZ2dwbG90KGFlcyhzaG9ydF9uYW1lXzEsIHJlZ2lvbiwgZmlsbCA9IHJlZ2lvbikpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyBzY2FsZV94X2xvZzEwKCkgKyAKICBsYWJzKHRpdGxlID0gIiIsIHkgPSAiIiwgZmlsbCA9ICIiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gICAKCiMjIyMgR0RQIHBlciBjYXBpdGEKCmBgYHs9aHRtbH0KPHNwYW4gc3R5bGUgPSAiY29sb3I6IHJlZDsiPkVkaXQgdGhlIHRpdGxlLCBhbmQgeWVhciBpZiBuZWNlc3NhcnkuPC9zcGFuPgpgYGAKYGBge3J9CmRmX3lvdXJkYXRhIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiAKICBkcm9wX25hKHNob3J0X25hbWVfMikgfD4gZmlsdGVyKGluY29tZSAhPSAiTm90IGNsYXNzaWZpZWQiKSB8PgogIGdncGxvdChhZXMoc2hvcnRfbmFtZV8yLCBmaWxsID0gZmFjdG9yKGluY29tZSwgbGV2ZWxzID0gSU5DT01FKSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDE1LCBjb2wgPSAiYmxhY2siLCBsaW5ld2lkdGggPSAwLjEpICsgCiAgc2NhbGVfeF9sb2cxMCgpICsKICBsYWJzKHRpdGxlID0gIiIsIGZpbGwgPSAiIikKYGBgCgpgYGB7PWh0bWx9CjxzcGFuIHN0eWxlID0gImNvbG9yOiByZWQ7Ij5FZGl0IHRoZSB0aXRsZSBhbmQgdGhlIHllYXIgaWYgbmVjZXNzYXJ5Ljwvc3Bhbj4KYGBgCmBgYHtyfQpkZl95b3VyZGF0YSB8PiBmaWx0ZXIoeWVhciAlaW4lIGMoMTk5MCwgMjAwMCwgMjAxMCwgMjAyMCkpIHw+IGZpbHRlcihyZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiAKICBkcm9wX25hKHNob3J0X25hbWVfMikgfD4gZmlsdGVyKHNob3J0X25hbWVfMiA+IDApIHw+IGZpbHRlcihpbmNvbWUgIT0gIk5vdCBjbGFzc2lmaWVkIikgfD4gCiAgZ2dwbG90KGFlcyhzaG9ydF9uYW1lXzIsIGZpbGwgPSBmYWN0b3IoeWVhcikpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNSwgY29sID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC4xKSArIAogIHNjYWxlX3hfbG9nMTAoKSArIGZhY2V0X3dyYXAofnllYXIpICsKICBsYWJzKHRpdGxlID0gIiIsIGZpbGwgPSAiIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgoqKk9ic2VydmF0aW9ucyBhbmQgUXVlc3Rpb25zOioqCgotICAgCgpgYGB7cn0KZGZfeW91cmRhdGEgfD4gZmlsdGVyKHllYXIgJWluJSBjKDE5OTAsIDIwMDAsIDIwMTAsIDIwMjApKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShzaG9ydF9uYW1lXzIpIHw+IGZpbHRlcihzaG9ydF9uYW1lXzIgPiAwKSB8PiBmaWx0ZXIoaW5jb21lICE9ICJOb3QgY2xhc3NpZmllZCIpIHw+IAogIGdncGxvdChhZXMoc2hvcnRfbmFtZV8yLCBmYWN0b3IoeWVhciksIGZpbGwgPSBmYWN0b3IoeWVhcikpKSArIAogIGdlb21fYm94cGxvdCgpICsgc2NhbGVfeF9sb2cxMCgpICsgbGFicyh5ID0gIiIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gICAKCmBgYHs9aHRtbH0KPHNwYW4gc3R5bGUgPSAiY29sb3I6IHJlZDsiPkVkaXQgdGhlIHRpdGxlLCBhbmQgdGhlIHllYXIgaWYgbmVjZXNzYXJ5Ljwvc3Bhbj4KYGBgCmBgYHtyfQpkZl95b3VyZGF0YSB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBmaWx0ZXIocmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZHJvcF9uYShzaG9ydF9uYW1lXzIpIHw+IGZpbHRlcihzaG9ydF9uYW1lXzIgPiAwKSB8PiBmaWx0ZXIoaW5jb21lICE9ICJOb3QgY2xhc3NpZmllZCIpIHw+IAogIGdncGxvdChhZXMoc2hvcnRfbmFtZV8yLCBmYWN0b3IoaW5jb21lLCBsZXZlbHMgPSBJTkNPTUUpLCBmaWxsID0gaW5jb21lKSkgKyAKICBnZW9tX2JveHBsb3QoKSArIHNjYWxlX3hfbG9nMTAoKSArIAogIGxhYnModGl0bGUgPSAiIiwgeSA9ICIiLCBmaWxsID0gIiIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKKipPYnNlcnZhdGlvbnMgYW5kIFF1ZXN0aW9uczoqKgoKLSAgIAoKYGBgez1odG1sfQo8c3BhbiBzdHlsZSA9ICJjb2xvcjogcmVkOyI+RWRpdCB0aGUgdGl0bGUgYW5kIHRoZSB5ZWFyIGlmIG5lY2Vzc2FyeS48L3NwYW4+CmBgYApgYGB7cn0KZGZfeW91cmRhdGEgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZmlsdGVyKHJlZ2lvbiAhPSAiQWdncmVnYXRlcyIpIHw+IAogIGRyb3BfbmEoc2hvcnRfbmFtZV8yKSB8PiBmaWx0ZXIoc2hvcnRfbmFtZV8yID4gMCkgfD4gCiAgZ2dwbG90KGFlcyhzaG9ydF9uYW1lXzIsIHJlZ2lvbiwgZmlsbCA9IHJlZ2lvbikpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyBzY2FsZV94X2xvZzEwKCkgKyAKICBsYWJzKHRpdGxlID0gIiIsIHkgPSAiIiwgZmlsbCA9ICIiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMjIyBTY2F0dGVycGxvdCBmb3IgQ292YXJpYXRpb24KCiMjIyMgU2NhdHRlcnBsb3Qgd2l0aCBhIHJlZ3Jlc3Npb24gbGluZQoKYGBgez1odG1sfQo8c3BhbiBzdHlsZSA9ICJjb2xvcjogcmVkOyI+RWRpdCB0aGUgdGl0bGUsIHRoZSBsYWJlbHMgb2YgeC0gYW5kIHktIGF4ZXMuPC9zcGFuPgpgYGAKYGBge3J9CmRmX3lvdXJkYXRhIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IAogIGRyb3BfbmEoc2hvcnRfbmFtZV8yLCBzaG9ydF9uYW1lXzEpIHw+CiAgZ2dwbG90KGFlcyhzaG9ydF9uYW1lXzIsIHNob3J0X25hbWVfMSkpICsgZ2VvbV9wb2ludChhZXMoY29sID0gcmVnaW9uKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSAneX54Jywgc2UgPSBGQUxTRSkgKwogIHNjYWxlX3hfbG9nMTAoKSArIHNjYWxlX3lfbG9nMTAoKSArCiAgbGFicyh0aXRsZSA9ICIiLAogICAgICAgeCA9ICIiLAogICAgICAgeSA9ICIiKQpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gICAKCiMjIyMgU3VtbWFyeSBvZiBhIGxpbmVhciBtb2RlbAoKYGBgez1odG1sfQo8c3BhbiBzdHlsZSA9ICJjb2xvcjogcmVkOyI+RWRpdCB5ZWFyIGlmIG5lY2Vzc2FyeS48L3NwYW4+CmBgYApgYGB7cn0KZGZfeW91cmRhdGEgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYShzaG9ydF9uYW1lXzIsIHNob3J0X25hbWVfMSkgfD4KICBsbShsb2cxMChzaG9ydF9uYW1lXzEpfmxvZzEwKHNob3J0X25hbWVfMiksIGRhdGEgPSBfKSB8PiBzdW1tYXJ5KCkKYGBgCgoqKk9ic2VydmF0aW9ucyBhbmQgUXVlc3Rpb25zOioqCgotICAgCg==